using System;
using System.Collections.Generic;
using System.Text;
using NBusiness.CodeDom;
using NBusiness.CodeDom.Compiler;
using NBusiness.ESharp.Compiler;

namespace NBusiness.ESharp
{
    [Serializable]
    internal class ESharpFamily : EntityFamily
    {        
        #region Attach
        protected override void Attach()
        {
            foreach (Entity e in Entities)
                (e as ICompileUnit).Attach();

            foreach (EntityFamily family in Families.Values)
                (family as ICompileUnit).Attach();
        } 
        #endregion

        #region Initialize Assignments
        protected override void InitializeAssignmentLogic()
        {
            //Family name
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.FamilyName,
                new AssignmentLogicHandler(AssignFamilyName)));
            
            //join
            Assignments.Add(new AssignmentLogic(
                 ESharpEntityElementTypes.FamilyJoin ));

            //Begin family
            Assignments.Add(new AssignmentLogic( ESharpEntityElementTypes.GroupBegin ));

            //Create an "entity"
            Assignments.Add(new AssignmentLogic( 
                ESharpEntityElementTypes.EntityDeclaration,
                new AssignmentLogicHandler(CreateNewEntity) ));

            //create a "model"
            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.ModelDeclaration,
                CreateNewModel));

            Assignments.Add(new AssignmentLogic(
                ESharpEntityElementTypes.GroupEnd));

            Assignments.Add(new AssignmentLogic( ESharpEntityElementTypes.WhiteSpace ));
            Assignments.Add(new AssignmentLogic( ESharpEntityElementTypes.Comment ));
        } 
        #endregion

        #region Assignments
        private void AssignFamilyName(object sender, AssignmentLogicEventArgs e)
        {
            if (string.IsNullOrEmpty(Name))
            {
                Name = e.Elements.Peek().Value;
            }
            else
            {
                EntityElement element = e.Elements.Peek();
                if (Families.ContainsKey(element.Value))
                {
                    (Families[element.Value] as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.FamilyName);
                }
                else
                {
                    EntityFamily f = new ESharpFamily();
                    f.Name = element.Value;
                    f.Parent = this;
                    Families.Add(f.Name, f);
                    (f as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.FamilyName);

                }
            }
        }

        private void CreateNewEntity(object sender, AssignmentLogicEventArgs e)
        {
            ESharpEntity entity = new ESharpEntity();
            entity.Parent = this;
            (entity as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.EntityDeclaration);

            bool match = false;
            foreach (Entity en in this.Entities)
            {
                if (entity.Name == en.Name)
                {
                    match = true;
                    break;
                }
            }

            if (!match)
                Entities.Add(entity);
            else
                OnBuildError(new ESharpBuildError(ESharpErrorCode.ES1001, (entity as ICompileUnit).Elements[0]));
        }

        private void CreateNewModel(object sender, AssignmentLogicEventArgs e)
        {
            ESharpEntityModel model = new ESharpEntityModel();
            model.Parent = this;
            (model as ICompileUnit).Build(e.Elements, ESharpEntityElementTypes.ModelDeclaration);

            bool match = this.Entities.Find(delegate(Entity en)
            {
                return model.Name == en.Name;
            }) != null;

            if (!match)
                Entities.Add(model);
            else
                OnBuildError(new ESharpBuildError(ESharpErrorCode.ES1001, (model as ICompileUnit).Elements[0]));
        }

        #endregion

        #region Get Element from child
        protected override EntityElement GetElementFromChild(string path, int line, int col)
        {
            EntityElement e = null;
            foreach (Entity entity in Entities)
            {
                e = (entity as ICompileUnit).GetElementByLocation(path, line, col);
                if (e != null) break;
            }

            if (e == null)
            {
                foreach (EntityFamily family in Families.Values)
                {
                    e = (family as ICompileUnit).GetElementByLocation(path, line, col);
                    if (e != null) break;
                }
            }

            return e;
        } 
        #endregion

        #region Get unit from child
        protected override ICompileUnit GetUnitFromChild(EntityElement element)
        {
            ICompileUnit unit = null;
            foreach (Entity entity in Entities)
            {
                unit = (entity as ICompileUnit).GetUnitByElement(element);
                if (unit != null) break;
            }

            if (unit == null)
            {
                foreach (EntityFamily family in Families.Values)
                {
                    unit = (family as ICompileUnit).GetUnitByElement(element);
                    if (unit != null) break;
                }
            }

            return unit;
        } 
        #endregion
    }
}
